﻿using Dycox.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;
using Dycox.Collections;

namespace Dycox.Windows.Forms
{
    [DefaultEvent("SelectedObjectChanged")]
    public class DetailsView : ListView
    {
        private static ImageList CommonImageList;

        private static void InitializeCommonImageList()
        {
            if (CommonImageList == null)
            {
                CommonImageList = new ImageList();

                CommonImageList.Images.Add("Expand", Properties.Resources.Collapsed);
                CommonImageList.Images.Add("Collapse", Properties.Resources.Expanded);
                CommonImageList.Images.Add("Field", Properties.Resources.Field);
                CommonImageList.Images.Add("Element", Properties.Resources.Element);
                CommonImageList.Images.Add(Properties.Resources.Object);
            }
        }

        ColumnHeader chName, chText;

        public DetailsView()
        {
            base.View = System.Windows.Forms.View.Details;
            base.HeaderStyle = ColumnHeaderStyle.Nonclickable;
            //base.OwnerDraw = true;
            base.GridLines = true;
            base.FullRowSelect = true;

            chName = base.Columns.Add("项目", 120);
            chText = base.Columns.Add("内容", 300);

            InitializeCommonImageList();
            base.SmallImageList = CommonImageList;
        }

        

        private object _selectedObject;

        [Browsable(false)]
        public object SelectedObject
        {
            get { return _selectedObject; }
            set
            {
                if (_selectedObject != value)
                {
                    _selectedObject = value;
                    RefreshObjectProperties();
                    OnSelectedObjectChanged(EventArgs.Empty);
                }
            }
        }

        public event EventHandler SelectedObjectChanged;

        protected virtual void OnSelectedObjectChanged(EventArgs e)
        {
            if (SelectedObjectChanged != null)
                SelectedObjectChanged(this, e);
        }

        private void RefreshObjectProperties()
        {
            object obj = _selectedObject;

            RefreshItems(obj);
            chText.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);

            int pw = this.ClientSize.Width - SystemInformation.VerticalScrollBarWidth - chName.Width;
            
            if (chText.Width < pw) chText.Width = pw;
        }

        private DetailsViewInstanceItem _root;

        private void RefreshItems(object obj)
        {
            Items.Clear();

            if (obj != null)
            {
                _root = new DetailsViewInstanceItem(obj);

                foreach (var item in _root.Items)
                {
                    InitializeItem(item);
                    Items.Add(item);
                }

            }
        }

        private void InitializeItem(DetailsViewItem item)
        {
            UpdateItemImage(item);

            item.IndentCount = item.Depth - 1;
        }

        private static void UpdateItemImage(DetailsViewItem item)
        {
            string key = "Field";

            if (item.Expandable)
            {
                if (item.IsExpanded)
                    key = "Collapse";
                else
                    key = "Expand";
            }

            item.ImageKey = key;
        }

        private int _columns = 1;

        [Category("Behavior"), DefaultValue(1)]
        public new int Columns
        {
            get { return _columns; }
            set
            {
                if (_columns != value)
                {
                    if (value < 1)
                        throw new ArgumentException("Columns cannot be less than 1.");

                    _columns = value;
                }
            }
        }

        protected override void OnDrawItem(DrawListViewItemEventArgs e)
        {
            //e.DrawBackground();
            base.OnDrawItem(e);
        }

        protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
        {
            e.DrawBackground();
            if ((e.ItemState & ListViewItemStates.Focused) == ListViewItemStates.Focused && e.ColumnIndex == 1)
                e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
            e.DrawText();
        }

        #region hide useless members

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new ListViewItemCollection Items
        {
            get { return base.Items; }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DefaultValue(typeof(View), "Details")]
        public new View View
        {
            get { return base.View; }
            set
            {
                if (value != System.Windows.Forms.View.Details)
                    throw new ArgumentException("Value of View property can only be Details.");

                base.View = value;
            }
        }

        [Browsable(false), DefaultValue(typeof(ColumnHeaderStyle), "Nonclickable")]
        public new ColumnHeaderStyle HeaderStyle
        {
            get { return base.HeaderStyle; }
            set { base.HeaderStyle = value; }
        }

        //[Browsable(false), DefaultValue(true)]
        //public new bool OwnerDraw
        //{
        //    get { return base.OwnerDraw; }
        //    set { base.OwnerDraw = value; }
        //}

        [Browsable(false), DefaultValue(true)]
        public new bool GridLines
        {
            get { return base.GridLines; }
            set { base.GridLines = value; }
        }

        [Browsable(false), DefaultValue(true)]
        public new bool FullRowSelect
        {
            get { return base.FullRowSelect; }
            set { base.FullRowSelect = value; }
        }

        [Browsable(false), DefaultValue(null)]
        public new ImageList SmallImageList
        {
            get { return null; }
            set
            {
                throw new InvalidOperationException();
            }
        }

        [Browsable(false), DefaultValue(null)]
        public new ImageList StateImageList
        {
            get { return null; }
            set { throw new InvalidOperationException(); }
        }

        #endregion

        #region overrides

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            var ht  = HitTest(e.Location);

            DetailsViewItem item = ht.Item as DetailsViewItem;
            
            if (item != null && item.Expandable)
            {
                ToggleExpanded(item);
            }

            base.OnMouseDoubleClick(e);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            var ht = HitTest(e.Location);

            if ((ht.Location & ListViewHitTestLocations.Image) == ListViewHitTestLocations.Image)
            {
                DetailsViewItem item = ht.Item as DetailsViewItem;

                if (item != null && item.Expandable)
                {
                    ToggleExpanded(item);
                }

            }

            base.OnMouseClick(e);
        }

        private void ToggleExpanded(DetailsViewItem item)
        {
            if (!item.IsExpanded)
            {
                Expand(item);
            }
            else
            {
                Collapse(item);
                item.IsExpanded = false;
            }

            UpdateItemImage(item);

        }

        private void Collapse(DetailsViewItem item)
        {
            foreach (var dvi in item.Items)
            {
                if (dvi.Expandable && dvi.IsExpanded)
                    Collapse(dvi);

                this.Items.Remove(dvi);
            }

        }

        private void Expand(DetailsViewItem item)
        {
            int index = item.Index;

            foreach (var dvi in item.Items)
            {
                InitializeItem(dvi);
                this.Items.Insert(++index, dvi);

                if (dvi.Expandable && dvi.IsExpanded)
                {
                    Expand(dvi);
                }
            }
            item.IsExpanded = true;

        }

        #endregion

    }

}
